import numpy as np  
import time
import sys 
import cv2

import proto.cameraobjectarray_pb2 as cameraobjectarray_pb2


class VehicleCount:
    def __init__(self, line_start,line_end,max_track_length,unupdated_timeout,
                 calculate_range_flag=True,
                 identification_range=30):  
        self.prev_time = time.time()  #帧计数器
        # 定义识别线线的起点和终点坐标
        self.line_start = line_start  # 起点
        self.line_end = line_end  # 终点
        self.counter = 0  # 计数器
        self.counter_id = 0  # 分配唯一 ID 的计数器
        self.buffer_tracks = {}  # 保存位置和时间的元组
        self.crossed_boxes = {}  # 用于存储每个框的交叉状态的字典
        self.calculate_range_flag = calculate_range_flag   #
        self.identification_range = identification_range  # 连续框判断误差（像素）
        self.max_track_length = max_track_length  # 最大轨迹长度
        self.unupdated_timeout = unupdated_timeout  # 未更新的轨迹存在时间（秒）
        self.last_updated = {}  # 初始化 last_updated 字典\
        
        
        self.line_start = np.array([295, 523])  # 起点
        self.line_end = np.array([636, 523])  # 终点
        
        self.way3_line_start = np.array([636, 523])  # way3起点
        self.way3_line_end = np.array([818, 523])  # 终点
        
        self.change_line_start=np.array([538,299])
        self.change_line_end=np.array([423,713])
        
        self.change3_line_start=np.array([621,373])
        self.change3_line_end=np.array([690,713])
        
        self.ill_line_start = np.array([295, 500])  # 起点
        self.ill_line_end = np.array([636, 500])  # 终点
        
        
        
        
    	
        
        self.way3_counter=0
        self.truck_counter=0
        
        self.ill_counter=0

        self.change_boxes={}
        self.change_counter=0
        
        self.people_counter=0
        self.ill_time=0
        self.ill_flag=False
        self.ill_type=0
        
        
        
        
        print("open ")

    def calculate_identification_range(self, y, frame_height, min_range=5, max_range=70):
        """
        根据 y 坐标动态计算识别范围。
        y: 车辆中心的 y 坐标
        frame_height: 视频帧的高度
        min_range: 最小识别范围
        max_range: 最大识别范围
        """
        return int(min_range + (max_range - min_range) * (y / frame_height))
    
    def estimate_cross_and_count(self,box_id,type):
    	if len (self.buffer_tracks[box_id])>1 and not self.crossed_boxes[box_id]:
    		if (self.buffer_tracks[box_id][-2][0][1]-self.line_start[1])*(self.buffer_tracks[box_id][-1][0][1]-self.line_start[1])<=0:    	
    			self.crossed_boxes[box_id]=True
    			if (self.buffer_tracks[box_id][-2][0][0] >self.line_start[0]) and (self.buffer_tracks[box_id][-1][0][0] <self.line_end[0]):
    				self.counter+=1
    				if type=='truck':
    					self.truck_counter+=1
    			elif (self.buffer_tracks[box_id][-2][0][0] >self.way3_line_start[0]) and (self.buffer_tracks[box_id][-1][0][0] <self.way3_line_end[0]):
    				self.way3_counter+=1
    				if type=='people':
    					self.people_counter+=1
       				
        	
        	
        	
    def change12_and_count(self,box_id,type):
    	if len (self.buffer_tracks[box_id])>1:
    		if (self.buffer_tracks[box_id][-2][0][1] > self.change_line_start[1]):
    			x1=self.change_line_start[0]
    			y1=self.change_line_start[1]
    			x2=self.change_line_end[0]
    			y2=self.change_line_end[1]
    			
    			x3=self.buffer_tracks[box_id][-2][0][0]
    			y3=self.buffer_tracks[box_id][-2][0][1]
    			
    			x4=self.buffer_tracks[box_id][-1][0][0]
    			y4=self.buffer_tracks[box_id][-1][0][1]
    			
    			pan1=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)
    			pan2=(x2-x1)*(y4-y1)-(y2-y1)*(x4-x1)
    			if pan1*pan2<=0:
    				if not self.change_boxes[box_id]:
    					self.change_boxes[box_id]=True
    					self.change_counter+=1
    				if y3>self.ill_line_start[1]:
    					self.ill_counter+=1
    def change3_and_count(self,box_id,type):
    	if len (self.buffer_tracks[box_id])>1:
    		if (self.buffer_tracks[box_id][-2][0][1] > self.change_line_start[1]):
    			x1=self.change3_line_start[0]
    			y1=self.change3_line_start[1]
    			x2=self.change3_line_end[0]
    			y2=self.change3_line_end[1]
    			
    			x3=self.buffer_tracks[box_id][-2][0][0]
    			y3=self.buffer_tracks[box_id][-2][0][1]
    			
    			x4=self.buffer_tracks[box_id][-1][0][0]
    			y4=self.buffer_tracks[box_id][-1][0][1]
    			
    			pan1=(x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)
    			pan2=(x2-x1)*(y4-y1)-(y2-y1)*(x4-x1)
    			if pan1*pan2<=0:
    				if y3>self.ill_line_start[1] and not self.ill_flag:
    					self.ill_time=self.prev_time
    					self.ill_type='ill change_line'
    			
    			
    		

    def remove_old_tracks(self):
        for id, track in list(self.buffer_tracks.items()):
            if len(track) > self.max_track_length:  # 如果轨迹过长
                track.pop(0)  # 移除最旧的位置
                #if time.time() - track[-1][1] > track_timeout:  #
                    #del buffer_tracks[id]  # 删除整个轨迹

        for id in list(self.buffer_tracks.keys()):
            if time.time() - self.last_updated[id] > self.unupdated_timeout:  #
                del self.buffer_tracks[id]  # 删除整个轨迹
                del self.last_updated[id]  # 删除对应的时间  

    def count(self,xobjarray : cameraobjectarray_pb2.cameraobjectarray,pic_mat : np):
        start_time = time.time()  # 记录处理开始时间
        frame_height = pic_mat.shape[0]  # 获取帧的高度
        curr_time = time.time()
        FPS = 1 / (curr_time - self.prev_time)
        self.prev_time = curr_time
        FPS_str = 'FPS: %s' % round(FPS, 2)
        # 绘制边界框和 FPS
        #cv2.putText(pic_mat, FPS_str, (5, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (34, 139, 34), 2)   
        for pobj in xobjarray.obj:

            center = np.array([(pobj.x + 0.5*pobj.w), (pobj.y + 0.5*pobj.h)], dtype=int)
            
            
            cv2.circle(pic_mat, tuple(center), radius=5, color=(0, 255, 255), thickness=-1)
            
            cv2.line(pic_mat, tuple(self.line_start), tuple(self.line_end), color=(255, 0, 0), thickness=6)
            
            cv2.line(pic_mat, tuple(self.change_line_start), tuple(self.change_line_end), color=(0, 255, 0), thickness=6)
            
            cv2.line(pic_mat, tuple(self.change3_line_start), tuple(self.change3_line_end), color=(0, 0, 255), thickness=6)
            
            
            cv2.line(pic_mat, tuple(self.ill_line_start), tuple(self.ill_line_end), color=(255, 255, 0), thickness=6)
            
            cv2.line(pic_mat, tuple(self.way3_line_start), tuple(self.way3_line_end), color=(0, 0, 0), thickness=6)
            
           # cv2.line(pic_mat, tuple(self.ill_line_s), tuple(self.ill_line_e), color=(255, 0, 255), thickness=6)

            # 动态计算识别范围
            identification_range = self.calculate_identification_range(center[1], frame_height) if self.calculate_range_flag else self.identification_range

            # 检查框 ID 是否已存在于缓冲区中
            box_id = None
            for id, past_positions in self.buffer_tracks.items():
                if len(past_positions) > 0 and np.linalg.norm(
                        past_positions[-1][0] - center) < identification_range:
                    box_id = id
                    break

            if box_id is None:
                # 分配一个新的 ID为盒子
                box_id = self.counter_id
                self.counter_id += 1
                self.buffer_tracks[box_id] = []
                self.crossed_boxes[box_id] = False  # 将交叉状态初始化为 False
                self.change_boxes[box_id]=False
                #self.ill_boxes[box_id]=False

            self.buffer_tracks[box_id].append((center, time.time()))  # 添加位置和当前时间
            self.last_updated[box_id] = time.time()  # 更新时间

            # 绘制检测框的ID
            cv2.putText(pic_mat, f'ID: {box_id}', (center[0], center[1] - 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2)

            # 检查框是否越界
            self.estimate_cross_and_count(box_id,pobj.type)
            
            
            # 检查框是否越界
            self.change3_and_count(box_id,pobj.type)
            
             # 检查框是否越界
            self.change12_and_count(box_id,pobj.type)



            # 如果框被标记为已越线，则绘制文本
            if self.crossed_boxes[box_id]:
                cv2.putText(pic_mat, 'crossed', (center[0], center[1] - 20), cv2.FONT_HERSHEY_SIMPLEX, 1,
                            (0, 255, 0), 2)
                
        # delete old tracker
        self.remove_old_tracks()

        #draw track
        for track in self.buffer_tracks.values():
            positions = [pos_time[0] for pos_time in track]  # 提取位置列表
            if len(positions) > 1:
                for i in range(1, len(positions)):
                    start_pos = positions[i - 1]
                    end_pos = positions[i]
                    cv2.line(pic_mat, tuple(start_pos), tuple(end_pos), (0, 255, 255), 4)  # 轨迹线条

        counter_str = 'Counter: %s' % self.counter
        counter_str = f"counter12:{self.counter},truck_counter:{self.truck_counter},ill_counter:{self.ill_counter},change_counter:{self.change_counter}"
       
        counter_str2=f"counter3:{self.way3_counter},peopel:{self.people_counter},ill_time:{self.ill_time},ill_type:{self.ill_type}"
        
        
        cv2.putText(pic_mat, counter_str, (5, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (34, 139, 34), 2)  # 将计数器放在框架上
        cv2.putText(pic_mat, counter_str2, (5, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (34, 139, 34), 2)  # 将计数器放在框架上
                

                
                
                    


    
    

    



    
